[PATCH] svm: fix RIP-relative addressing in invlpg emulation
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 27 Nov 2006 10:06:41 +0000 (10:06 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 27 Nov 2006 10:06:41 +0000 (10:06 +0000)
RIP-relative addressing as relative to the beginning of the next (or,
in other word, the end of the current) instruction.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
xen/arch/x86/hvm/svm/emulate.c
xen/arch/x86/hvm/svm/svm.c
xen/include/asm-x86/hvm/svm/emulate.h

index 5adaa8d50dfac3096c7eb5735af5380b202defc8..504bafe7db95e31dccb72a35709fe0c99957acb2 100644 (file)
@@ -145,8 +145,8 @@ static inline u64 hv_is_canonical(u64 addr)
 
 
 unsigned long get_effective_addr_modrm64(struct vmcb_struct *vmcb, 
-        struct cpu_user_regs *regs, const u8 prefix, const u8 *operand, 
-        u8 *size)
+        struct cpu_user_regs *regs, const u8 prefix, int inst_len,
+        const u8 *operand, u8 *size)
 {
     unsigned long effective_addr = (unsigned long) -1;
     u8 length, modrm_mod, modrm_rm;
@@ -191,17 +191,8 @@ unsigned long get_effective_addr_modrm64(struct vmcb_struct *vmcb,
             *size = 1;
             break;
         }
-
-        CHECK_LENGTH64(*size + (u8)sizeof(u32));
-
-        memcpy (&disp, operand + 1, sizeof (u32));
-        *size += sizeof (u32);
-        if (vmcb->cs.attributes.fields.l) // 64-bit mode
-            return vmcb->rip + disp;
-        else
-            return disp;
-
 #if __x86_64__
+        /* FALLTHRU */
     case 0xD:
         if (0 < modrm_mod)
         {
@@ -209,19 +200,20 @@ unsigned long get_effective_addr_modrm64(struct vmcb_struct *vmcb,
             effective_addr = regs->r13;
             break;
         }
+#endif
 
         CHECK_LENGTH64(*size + (u8)sizeof(u32));
 
         memcpy (&disp, operand + 1, sizeof (u32));
         *size += sizeof (u32);
 
+#if __x86_64__
         /* 64-bit mode */
-        if (vmcb->cs.attributes.fields.l)
-            return vmcb->rip + disp;
-        else
-            return disp;
-
+        if (vmcb->cs.attributes.fields.l && (vmcb->efer & EFER_LMA))
+            return vmcb->rip + inst_len + *size + disp;
 #endif
+        return disp;
+
     default:
         effective_addr = DECODE_GPR_VALUE(vmcb, regs, modrm_rm);
 
index f2a8659136de7fce5221df129921743eddaad082..546c66f9fae75c7de0e4351162d421fa12a43eb2 100644 (file)
@@ -2053,10 +2053,10 @@ void svm_handle_invlpg(const short invlpga, struct cpu_user_regs *regs)
 
         /* 
          * Decode memory operand of the instruction including ModRM, SIB, and
-         * displacement to get effecticve address and length in bytes.  Assume
+         * displacement to get effective address and length in bytes.  Assume
          * the system in either 32- or 64-bit mode.
          */
-        g_vaddr = get_effective_addr_modrm64(vmcb, regs, prefix, 
+        g_vaddr = get_effective_addr_modrm64(vmcb, regs, prefix, inst_len,
                                              &opcode[inst_len], &length);
 
         inst_len += length;
index 4d15652afee8125b78531051d7cba1415abbf05a..3bb12081282d8013e117bcfcac4297451766f25b 100644 (file)
@@ -77,8 +77,8 @@ enum instruction_index {
 
 
 extern unsigned long get_effective_addr_modrm64(struct vmcb_struct *vmcb, 
-        struct cpu_user_regs *regs, const u8 prefix, const u8 *operand, 
-        u8 *size);
+        struct cpu_user_regs *regs, const u8 prefix, int inst_len,
+        const u8 *operand, u8 *size);
 extern unsigned long get_effective_addr_sib(struct vmcb_struct *vmcb, 
         struct cpu_user_regs *regs, const u8 prefix, const u8 *operand, 
         u8 *size);